import numpy as np

# 激活函数
def step_function(x):
    return np.array(x>0,dtype=np.int32)

def sigmoid(x):
    return 1/(1+np.exp(-x))

def relu(x):
    return np.maximum(0,x)

def sigmoid_grad(x):
     return (1.0-sigmoid(x))*sigmoid(x)

# 输出层激活函数

# 回归问题输出层激活函数
def identity_function(x):
    return x
# 分类问题输出层激活函数
def softmax(x):
    if x.ndim == 2:
        x = x.T
        x = x - np.max(x,axis=0)
        y = np.exp(x)/np.sum(np.exp(x),axis=0)
        return y.T
    x = x - np.max(x)
    return np.exp(x)/np.sum(np.exp(x))

# 损失函数
# 1.均分误差函数
def mean_squared_error(y,t):
    '''均方误差损失函数
    params:
    -------------------
        y: 神经网络的输出
        t: 监督数据（标签）
    return:
    -------------------
        表示样本和监督数据的偏离程度
    '''
    return 0.5*np.sum((y-t)**2)

# 2.交叉熵函数
def cross_entropy_error(y,t):
    '''通用交叉熵函数
    params:
    ---------------
        y: 神经网络输出（可以是批量样本的输出，也可以是单个样本的）
        t: 监督数据，可以是批量的，也可以是单个的；既可以是one-hot，也可以不是
    return:
    --------------
        神经网络的输出与监督数据的交叉熵
    '''
    if y.ndim == 1:
        t = t.reshape(1,t.size)
        y = y.reshape(1,y.size)
    # 监督数据为one-hot-vector时，转换为正确的标签的索引
    if t.size == y.size:
        t = t.argmax(axis=1)

    batch_size = y.shape[0]
    # 获取神经网络输出中与监督数据（非one-hot)位置对应值
    y_i_t = y[np.arange(batch_size),t]
    return -np.sum(np.log(y_i_t+1e-7))/batch_size
